#include "FastNetDeviceThread.hh"

namespace requestDevices
{

FastNetDeviceThread::FastNetDeviceThread(FastNetDevice * m) : notReady(true), master(m)
{
	pthread_attr_t attr;
	pthread_attr_init(&attr);
  	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  	if(pthread_create(&coreThread, &attr, startDevice,(void*) this)) {
		std::cerr << "pthread_create failed" << strerror(errno) << std::endl;
    	std::exit(1);
	}
/*  	
    cpu_set_t set;
  	CPU_ZERO(&set);
  	CPU_SET(procNum++, &set);
  	std::cout << "Setting affinity of thread " << coreThread << " to proc " << procNum - 1 << "." << std::endl;
  	if(pthread_setaffinity_np(coreThread, sizeof(set), &set) != 0) {
    	std::cerr << "Affinity not set: " << strerror(errno) << std::endl;
  	}
	*/
}

FastNetDeviceThread::~FastNetDeviceThread()
{
}

void 
FastNetDeviceThread::setReady()
{
	Synchronized::Scope mutex(this); 
	notReady = false; 
	notify();
}

void
FastNetDeviceThread::process()
{
	{
	Synchronized::Scope mutex(this);
	while(notReady) {
		wait();
	}
	}
	while(true) {
		socket_t sock = master->getActiveSocket();
		if(sock >= 0) {
			// data from an established connection
	  		char * buffer = new char[BUFSIZE];
	  		int numBytes=0;
	  		if((numBytes = recv(sock, buffer, BUFSIZE, 0)) <= 0) {
	  			if(numBytes < 0) {
					std::cerr << "Receive error: " << strerror(errno) << std::endl;
	      			exit(1);
	    		}		
	    		shutdown(sock, SHUT_RDWR);
	    		if(close(sock) < 0) {
	    			perror("Close");
	    		}
	    		delete[] buffer;
	    		master->clearSock(sock);
	  		}
	  		else {
	    		// process data
	    			#ifndef DEBUG
	    		std::pair<lagniappe::CoreOp *, std::string> * dest = master->getDest();
	    		if(dest == NULL) {
	      			delete[] buffer;
	    		}
	    		else if(dest->first == NULL) {
	    			delete[] buffer;
	    		}
	    		else {
	      			// actually send out an RCon
	      			assert(buffer != NULL);
	      			NetRequest * netReq = new NetRequest(buffer, sock, numBytes);
	      			lagniappe::RCon * newRCon = new lagniappe::RCon(dest->first, static_cast<lagniappe::RData *>(netReq), dest->second, sizeof(netReq));
	      			dest->first->run(newRCon);
	    		}
	      			#endif
	      			#ifdef DEBUG
	      			std::cout << this << " " << buffer << std::endl;
	      			#endif 
	  		}
		}	 
		
	}
}

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

void * 
startDevice(void * arg)
{

	FastNetDeviceThread * nicThread = static_cast<FastNetDeviceThread *>(arg);
	nicThread->process();
	return NULL;
}

#ifdef __cplusplus
}
#endif /* __cplusplus */
	
}
